<?php
/**
 * 后台 panx 代理（客户）的管理
 * Author: lyun
 * Date: 2018/3/30
 * Created by Panxsoft.
 */

namespace App\Http\Controllers\Admin\Panx;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Admin\Panx\Customer\CustomerIndexRequest;
use App\Http\Requests\Admin\Panx\Customer\CustomerOperateRequest;
use App\Http\Requests\Admin\Panx\Customer\CustomerStoreRequest;
use App\Http\Requests\Admin\Panx\Customer\CustomerUpdateRequest;
use App\Models\Admin\CustomerAdmin;
use App\Models\Admin\PanxAdmin;
use App\Models\Customer\Customer;
use App\Models\OpenWechat\Authorizer;
use App\Models\Panx\Category;
use App\Models\Store\Store;
use App\Services\Locale\Language;
use App\Services\Repositories\StoreAdminRepository;
use App\Services\Utils\RequestParam;
use App\Services\Utils\Transaction;
use App\Services\Youzan\AuthorizerableService;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Auth;

class CustomerController extends ApiController
{

    const ROUTE_NAMES = [
        'index'        => 'api.admin.panx.customer.index',
        'store'        => 'api.admin.panx.customer.store',
        'update'       => 'api.admin.panx.customer.update',
        'patch_status' => 'api.admin.panx.customer.patch.status',
    ];

    /**
     * @test
     * @see CustomerControllerTest::test_index()
     *
     * @param CustomerIndexRequest $request
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function index(CustomerIndexRequest $request)
    {
        // 超管才能操作的
        $this->checkIsTrue(PanxAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        $keyword = $request->keyword;

        /** @var LengthAwarePaginator $customers */
        $customers = (new Customer)
            ->filterProviderType($request->provider_type)
            ->filterShowVirtual($request->show_virtual)
            ->filterIsDeleted($request->is_deleted)
            ->filterHasHair($request->has_hair)
            ->filterIsDebug($request->is_debug)
            ->columnsKeywordOrLike(['name', 'legal_person', 'telephone', 'contacts', 'phone',], $keyword)
            ->filterAccount($keyword)
            ->with('categories', 'customerAdmins')
            ->latest()
            ->paginate($request->per_page ?: 15);

        $customers = $this->transformCustomer($customers);

        return $this->response(compact('customers'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        /** @var Collection $authorizers */
        $authorizers = (new Authorizer)
            ->where('canceled', Authorizer::STATUS_AUTH)
            ->latest()
            ->get(['id', 'nick_name']);

        $authorizers->prepend([
            'id'        => 0,
            'nick_name' => trans('admin.no_authorizer'),
        ]);

        $categories = (new Category)
            ->where('parent_id', Category::TOP_CATEGORY)
            ->get(['id', 'const', Language::getLocalNameColumn()]);

        $languages = Language::LANGUAGE;

        return $this->response(compact('authorizers', 'categories', 'languages'));
    }

    /**
     * Store a newly created resource in storage.
     *
     * @test
     *
     * @param  CustomerStoreRequest $request
     * @return \Illuminate\Http\Response
     * @throws \Exception
     */
    public function store(CustomerStoreRequest $request)
    {
        // 超管才能操作的
        $this->checkIsTrue(PanxAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        $stored = Transaction::handle(function () use ($request) {
            // 开通代理和代理超管账号
            /** @var Customer $customer */
            $customer = $this->storeCustomer($request);

            $customer->admin = $this->storeCustomerAdmin($request, $customer);

            return $customer;
        });

        return $this->response(compact('stored'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @test
     * @see CustomerControllerTest::test_update()
     *
     * @param  CustomerUpdateRequest $request
     * @param  int $id
     * @return \Illuminate\Http\Response
     *
     * @throws \Exception
     */
    public function update(CustomerUpdateRequest $request, $id)
    {
        // 超管才能操作的
        $this->checkIsTrue(PanxAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        /** @var Customer $customer */
        $customer = Customer::find($id);
        $this->checkItemExist($customer, trans('admin.customer'));

        $customer_data = $this->assembleCustomerUpdateData($request);
        $category_ids = $this->assembleCategoryIdAndPriority($request->operate_category);

        $updated = Transaction::handle(function () use ($customer_data, $customer, $category_ids) {
            if ($customer->isAuthorizerChanged($customer_data['authorizer_id'])) {
                (new StoreAdminRepository)->resetCustomerStoreAdminsWechatUserBinding($customer);
            }

            $customer->update($customer_data);

            $customer->categories()->sync($category_ids);

            if ($customer_data['has_youzan'] === Customer::NO_YOUZAN) {
                // 清理客户的有赞商品和有赞订单
                (new AuthorizerableService)->deleteYouzan($customer);

                // 清理店铺有赞授权
                $this->deleteStoreYouzan($customer);
            }

            return true;
        });

        return $this->response(compact('updated'));
    }

    /**
     * 启用和禁用客户
     *
     * @test
     * @see CustomerControllerTest::test_patch_status()
     *
     * @param CustomerOperateRequest $request
     * @param int $customer_id
     * @return array|\Illuminate\Http\Response
     *
     * @throws \Exception
     */
    public function patchStatus(CustomerOperateRequest $request, $customer_id)
    {
        // 超管才能操作的
        $this->checkIsTrue(PanxAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        /** @var Customer $customer */
        $customer = Customer::find($customer_id);
            $this->checkItemExist($customer, trans('admin.customer'));

        $updated = $customer->update(['is_deleted' => $request->is_deleted]);

        return $this->response(compact('updated', 'customer'));
    }

    /**
     * @deprecated (前端debug登录了！)
     *  panx 后台免登录访问客户的后台
     *
     * @param $customer_id
     * @return array|\Illuminate\Http\Response
     * @throws \Exception
     */
    public function loginCustomerAdmin($customer_id)
    {
        // 超管才能操作的
        $this->checkIsTrue(PanxAdmin::checkIsSuperMan(), trans('admin.is_super_man'));

        /** @var Customer $customer */
        $customer = Customer::find($customer_id);
            $this->checkItemExist($customer, trans('admin.customer'));

        /** @var CustomerAdmin $admin */
        $admin = $customer->customerAdmins()
            ->oldest()
            ->with('customer.categories')
            ->first();
        $this->checkItemExist($admin, trans('admin.customer_admin'));

        /**
         * @see JWTGuard::login()
         */
        $token = Auth::guard(CustomerAdmin::GUARD_NAME)->login($admin);

        $admin->provider_type = $admin->customer->provider_type ?? null;
        $admin->has_hair = $admin->customer->has_hair ?? null;
        $admin->has_youzan = $admin->customer->has_youzan ?? null;
        $admin->store_id = null;

        $admin->addHidden(['customer', 'roles', 'permissions']);

        // 返回管理员的角色和权限
        $roles = $admin->roles;
        $permissions = $admin->getAllPermissions();

        return $this->response(compact('token','admin', 'roles', 'permissions'));
    }

    /**
     * @param LengthAwarePaginator $customers
     * @return LengthAwarePaginator
     */
    private function transformCustomer(LengthAwarePaginator $customers)
    {
        $customers->transform(function (Customer $customer) {
            $first_admin = $customer->customerAdmins->first();

            $customer->account = $first_admin->account ?? null;
            $customer->language = $first_admin->language ?? Language::ZH_CN;

//            $customer->addHidden('oldestSuperAdmins');
            return $customer;
        });

        return $customers;
    }

    /**
     * @param CustomerStoreRequest $request
     *
     * @return mixed
     * @throws \Exception
     */
    private function storeCustomer(CustomerStoreRequest $request)
    {
        $customer_data = $this->assembleCustomerStoreData($request);
        $category_ids = $this->assembleCategoryIdAndPriority($request->operate_category);

        /** @var Customer $customer */
        $customer = Customer::create($customer_data);
        $customer->categories()->attach($category_ids);

        return $customer;
    }

    /** customers表的数据组装
     *
     * @param CustomerStoreRequest $request
     * @return array
     */
    private function assembleCustomerStoreData(CustomerStoreRequest $request)
    {
        $data = [
            'name'             => $request->name,
            'legal_person'     => $request->legal_person,
            'telephone'        => $request->telephone,
            'contacts'         => $request->contacts,
            'phone'            => $request->phone,
            'license'          => $request->license,
            'address'          => $request->address,
            'division_percent' => $request->division_percent,
            'provider_type'    => $request->provider_type, // 目前有虚拟客户和普通客户
            'authorizer_id'    => $request->authorizer_id ?? 0,
            'has_hair'         => 0, // 功能移除
            'province'         => $request->province,
            'city'             => $request->city,
            'district'         => $request->district,
            'is_debug'         => $request->is_debug ?? 0,
        ];

        $data = $this->normalizeOpenYouzanData($request, $data);

        $params = RequestParam::normalize([
            'dev_acnt_num', 'water_mark', 'show_virtual', 'has_youzan'
        ], $data);

        return $params;
    }

    /**
     * customer_admins表的数据组装
     * @param CustomerStoreRequest $request
     * @param Customer $customer
     * @return array
     */
    private function assembleCustomerAdminData(CustomerStoreRequest $request, Customer $customer)
    {
        return [
            'customer_id' => $customer->id,
            'name'        => $request->name,
            'account'     => $request->account,
            'password'    => $request->password,
            'phone'       => $request->phone,
            'email'       => $request->email,
            'language'    => $request->language,
            'born_at'     => Carbon::now(),
        ];
    }

    /**
     * @param CustomerUpdateRequest $request
     * @return array
     */
    private function assembleCustomerUpdateData(CustomerUpdateRequest $request)
    {
        $data = [
            'name'             => $request->name,
            'legal_person'     => $request->legal_person,
            'telephone'        => $request->telephone,
            'contacts'         => $request->contacts,
            'phone'            => $request->phone,
            'address'          => $request->address,
            'division_percent' => $request->division_percent,
            'show_virtual'     => $request->show_virtual,
            'provider_type'    => $request->provider_type,
            'has_hair'         => 0,
            'province'         => $request->province,
            'city'             => $request->city,
            'district'         => $request->district,
            'is_debug'         => $request->is_debug ?? 0
        ];

        $data = $this->normalizeOpenYouzanData($request, $data);

        $params = RequestParam::normalize([
            'authorizer_id', 'dev_acnt_num', 'is_deleted', 'water_mark', 'license'
        ], $data);

        return $params;
    }

    /**
     * @param CustomerStoreRequest $request
     * @param Customer $customer
     * @return CustomerAdmin
     */
    private function storeCustomerAdmin(CustomerStoreRequest $request,
                                        Customer $customer): CustomerAdmin
    {
        $customer_admin_data = $this->assembleCustomerAdminData($request, $customer);

        /** @var CustomerAdmin $customer_admin */
        $customer_admin = CustomerAdmin::create($customer_admin_data);

        // 分配超管角色
        $customer_admin->assignRole(CustomerAdmin::SUPER_MAN);

        return $customer_admin;
    }

    /**
     * @param array $category_ids
     * @return array
     */
    private function assembleCategoryIdAndPriority(array $category_ids)
    {
        $categories = (new Category)
            ->whereIn('id', $category_ids)
            ->pluck('priority', 'id')
            ->all();

        $data = [];

        // 这里update（）会更新customer类别的优先级！
        foreach ($categories as $category_id => $priority) {
            $data[$category_id] = ['priority' => $priority];
        }

        return $data;
    }

    /**
     * @param CustomerUpdateRequest|CustomerStoreRequest|Request $request
     * @param $data
     *
     * @return mixed
     */
    private function normalizeOpenYouzanData(Request $request, array $data): array
    {
        $has_youzan = $request->has('has_youzan')
            && ((int) $request->has_youzan === Customer::HAS_YOUZAN);
        $is_normal_customer = (int) $request->provider_type === Customer::PROVIDER_TYPE_NORMAL;

        if ($has_youzan && $is_normal_customer) {
            $data['has_youzan'] = $request->has_youzan;
        } else {
            $data['has_youzan'] = Customer::NO_YOUZAN;
            $data['youzan_authorizer_id'] = Customer::NO_YOUZAN;
        }

        return $data;
    }

    /**
     * @param Customer $customer
     */
    private function deleteStoreYouzan(Customer $customer)
    {
        $customer->stores()->update([
            'youzan_authorizer_id' => Store::NO_YOUZAN,
            'has_youzan'           => Store::NO_YOUZAN,
        ]);

        $customer->stores->each(function(Store $store) {
            // 清理店铺有赞商品和有赞订单
            (new AuthorizerableService)->deleteYouzan($store);
        });
    }

}
